#include "GameDrawer.hpp"

GameDrawer* GameDrawer::currentInstance = 0;

GameDrawer* GameDrawer::Instance(){
    if(currentInstance == 0)
        currentInstance = new GameDrawer;
    return currentInstance;
}

GameDrawer::GameDrawer(){
    pixelOffsetY = pixelOffsetX = 0;
    startTileX = startTileY = 0;
}

void GameDrawer::setWindow(sf::RenderWindow* window){
    renderWindow = window;
}

bool GameDrawer::loadTextures(){
    spriteManager.loadSprites("sprites.dat");
    return true;
}

/** 
* Calculates the map offsets relative to the camera.
*/
void GameDrawer::calculateOffset(Camera* camera){
    screenWidth = camera->getWidth() / 32 + 1;
    screenHeight = camera->getHeight() / 32 + 2;

    startTileX = camera->getX() / 32 - screenWidth / 2;
    startTileY = (camera->getY() / 32) - screenHeight / 2;
    
    pixelOffsetX = camera->getX() % 32;
    pixelOffsetY = camera->getY() % 32;

    if(startTileX < 0){
        pixelOffsetX += startTileX * 32;
        screenWidth += startTileX * camera->getScale();
        startTileX = 0;
    }
    if(startTileY < 0){
        pixelOffsetY += startTileY * 32;
        screenHeight += startTileY * camera->getScale();
        startTileY = 0;
    }

    mapPixelOffsetX = pixelOffsetX;
    mapPixelOffsetY = pixelOffsetY;
    
    if(startTileX > 3){
        startTileX -= 3;
        screenWidth += 3;
        mapPixelOffsetX += 3 * 32;
        pixelOffsetX += 3*32 + startTileX * 32;
    }else if(startTileX > 0){
        screenWidth += startTileX;
        mapPixelOffsetX += startTileX * 32;
        pixelOffsetX += startTileX * 32;
        startTileX = 0;
    }

    if(startTileY > 3){
        startTileY -= 3;
        screenHeight += 3;
        mapPixelOffsetY += 3 * 32;
        pixelOffsetY += 3*32 + startTileY * 32;
    }else if(startTileY > 0){
        screenHeight += startTileY;
        mapPixelOffsetY += startTileY * 32;
        pixelOffsetY += startTileY * 32;
        startTileY = 0;
    }
    
}

/** 
* Draws the map background layers.
*/
void GameDrawer::drawMapBackground(Map* map, Camera* camera){
	calculateOffset(camera);
	drawMapLayer(map, camera, 0);
	drawMapLayer(map, camera, 1);
	drawMapLayer(map, camera, 2);
}

/** 
* Draws the map foreground layers.
*/
void GameDrawer::drawMapForeground(Map* map, Camera* camera){
	drawMapLayer(map, camera, 3);
	drawMapLayer(map, camera, 4);
}

/** 
* Draws a map layer to the screen.
* @param layer >Layer index to draw.
*/
void GameDrawer::drawMapLayer(Map* map, Camera* camera, byte layer){

	sf::Transform mapScale = sf::Transform().scale(camera->getScale(), camera->getScale());
	for(int i = startTileY; i < map->height && i < startTileY + screenHeight / camera->getScale() + 1; i++){
		for(int j = startTileX; j < map->width && j < startTileX + screenWidth / camera->getScale() + 1; j++){
			if(map->tiles[i * map->width + j][layer] != NO_SPRITE){
				sf::Transform mapPosition = mapScale;
                
				mapPosition *= sf::Transform().translate((j - startTileX)*32 - mapPixelOffsetX, (i - startTileY)*32 - mapPixelOffsetY);
				renderWindow->draw(*spriteManager.getSprite(map->tiles[i * map->width + j][layer]), mapPosition);
			}
		}
	}

}

GameDrawer::~GameDrawer(){
    renderWindow = 0;
    currentInstance = 0;
}